﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using UnityEngine;

public class TextureUtils {
    public static Texture CreateEmptyTexture() {
        Texture2D empty = new Texture2D(800, 600,TextureFormat.ARGB32,false);

        return empty;
    }
    public static Color[] CreateColors(int count) {
        Color[] colors = new Color[count];
        for (int i = 0; i < count; i++)
        {
            var c = colors[i];
            c.r = 0.0f;
            c.g = 0.0f;
            c.b = 0.0f;
            c.a = 0.0f;
            colors[i] = c;
        }
        return colors;
    }
    /// <summary>
    /// 复制（克隆）一个Texture，可以避开限制，例如：UnityException: Texture 'body_1' is not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings.
    /// </summary>
    /// <param name="tex"></param>
    /// <returns></returns>
    public static Texture2D CopyTexture(Texture2D tex)
    {

        Texture2D png = new Texture2D(tex.width, tex.height, tex.format, false);
        Graphics.CopyTexture(tex, png);
        
        return png;

    }

    public static Texture CopyTexture(Texture tex)
    {

        Texture2D png = new Texture2D(tex.width, tex.height,TextureFormat.ARGB32, false);
        Graphics.CopyTexture(tex, png);

        return png;

    }
    public static Texture CopyTexture(Texture tex,int width,int height,int offsetX,int offsetY)
    {
        var tex2D = TextureToTexture2D(tex);
        Texture2D png = new Texture2D(width, height, TextureFormat.ARGB32, false);
        Color[] colors = png.GetPixels();
        for(int i=0;i<colors.Length;i++)
        {
            Color c = colors[i];
            c.r = 0;
            c.g = 0;
            c.b = 0;
            c.a = 0;//TODO:现在好像，无法带alpha通道
            colors[i] = c;
        }
        png.SetPixels(colors);
        tex2D = MergeTexture(png,tex2D,offsetX,offsetY,true);
        ////Graphics.CopyTexture(tex, png);


        return tex2D;
    }

    #region 图像操作帮助方法
    public static Texture2D T2D(Texture tex)
    {
        return TextureToTexture2D(tex);
    }
    /// <summary>
    /// Texture转换成Texture2D...
    /// </summary>
    /// <param name="texture"></param>
    /// <returns></returns>
    public static Texture2D TextureToTexture2D(Texture texture)
    {
        if (texture == null) return null;
        Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
        RenderTexture currentRT = RenderTexture.active;
        RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
        Graphics.Blit(texture, renderTexture);

        RenderTexture.active = renderTexture;
        texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        texture2D.Apply();

        RenderTexture.active = currentRT;
        RenderTexture.ReleaseTemporary(renderTexture);
        return texture2D;
    }


    /// <summary>
    /// 能融合的一个方法，另一个快速融合方法，待实现
    /// </summary>
    /// <param name="tt1"></param>
    /// <param name="tt2"></param>
    /// <param name="offsetX"></param>
    /// <param name="offsetY"></param>
    /// <returns></returns>
    [System.Obsolete("不够快的方法，请调用另一个同名方法")]
    public Texture2D MergeTexture_(Texture2D tt1, Texture2D tt2, int offsetX, int offsetY)
    {

        Texture2D newTex = new Texture2D(tt1.width, tt1.height, TextureFormat.ARGB32, false);

        newTex.SetPixels(tt1.GetPixels());

        for (int x = 0; x < tt2.width; x++)
        {
            for (int y = 0; y < tt2.height; y++)
            {
                var PixelColorFore = tt2.GetPixel(x, y) * tt2.GetPixel(x, y).a;
                var newY = tt1.height - offsetY - tt2.height + y;
                var PixelColorBack = tt1.GetPixel(x + offsetX, newY) * tt1.GetPixel(x + offsetX, newY).a;
                newTex.SetPixel(x + offsetX, newY, PixelColorFore + PixelColorBack);
            }
        }
        newTex.Apply();
        //System.IO.File.WriteAllBytes(Application.dataPath + "/" + tt1.name + ".png", newTex.EncodeToPNG());
        //GameObject.Find("obj001").GetComponent<Renderer>().material.mainTexture = newTex;
        return newTex;
    }
    static Color GetColor(Color[] colors, int x, int y)
    {
        int columnCount = colors.Length / y;
        return colors[y * columnCount + x];
    }
    public Texture2D MergeTexture_2(Texture2D tt1, Texture2D tt2, int offsetX, int offsetY)
    {
        Texture2D newTex = new Texture2D(tt1.width, tt1.height, TextureFormat.ARGB32, false);

        //??????? set 一下？？？？？ 是为了做一个底图。。。。。。
        newTex.SetPixels(tt1.GetPixels());

        Color[] colors = tt2.GetPixels();
        for (int x = 0; x < tt2.width; x++)
        {
            for (int y = 0; y < tt2.height; y++)
            {
                var PixelColorFore = GetColor(colors, x, y) * GetColor(colors, x, y).a;
                var newY = tt1.height - offsetY - tt2.height + y;
                var PixelColorBack = tt1.GetPixel(x + offsetX, newY) * tt1.GetPixel(x + offsetX, newY).a;
                newTex.SetPixel(x + offsetX, newY, PixelColorFore + PixelColorBack);
            }
        }
        newTex.Apply();
        return newTex;
    }
    public static Texture2D MergeTextureByTransform(Texture2D t1, Texture2D t2, int posX, int posY) {
        int expWidth = t2.width + posX;
        int expHeight = t2.height + posY;
        int width = Mathf.Max(t1.width, expWidth);
        int height = Math.Max(t1.height, expHeight);
        Texture2D newTex = new Texture2D(width, height, TextureFormat.ARGB32, false);


        Color[] colorsCanvas = CreateColors(width * height);
        
        Color[] colorsT1 = t1.GetPixels();
        Color[] colorsT2 = t2.GetPixels();
        //无offset，所以不会越界？？
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                int cursor = x + y * width;
                if (IsInbound(x, y, t1.width, t1.height))
                {
                    int c1 = x + y * t1.width;
                    colorsCanvas[cursor] += colorsT1[c1];
                }

                int realPos = x - posX; //当前画布位置，减去偏移起点，即是所需拼合的点
                int realPosY = y - posY;
                
                if (IsInbound(realPos, realPosY, t2.width, t2.height)) {
                    int c2 = realPos  + realPosY * t2.width;

                    colorsCanvas[cursor] += colorsT2[c2];
                }
            }
        }
        newTex.SetPixels(colorsCanvas);
        newTex.Apply();
        return newTex;


    }
    static bool  IsInbound(int cx,int cy,int width, int height) {
        return cx >= 0 && cy >= 0 && cx < width && cy < height;
    }
    public static Texture2D LerpTexture(Texture2D mainTex, Color[] colors)
    {
        int width = mainTex.width;
        int height = mainTex.height;
        Texture2D newTex = new Texture2D(mainTex.width, mainTex.height, TextureFormat.ARGB32, false);
        Color[] colorMerge = new Color[width * height];
        Color[] colorsBase = mainTex.GetPixels();
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++)
            {
                int cursor = x + y * width;
                Vector3 blendColor = Vector3.Lerp(colorsBase[cursor].rgb(), colors[cursor].rgb(), colors[cursor].a);
                colorMerge[cursor].r = blendColor.x;
                colorMerge[cursor].g = blendColor.y;
                colorMerge[cursor].b = blendColor.z;
                colorMerge[cursor].a = colorsBase[cursor].a;
            }

        newTex.SetPixels(colorMerge);
        newTex.Apply();
        return newTex;
    }
    /// <summary>
    /// 直接用color融合进主材质，目前，要保证提取颜色的材质和主材质尺寸一致(用下面的方法）
    /// </summary>
    /// <param name="src"></param>
    /// <param name="colors"></param>
    /// <returns></returns>
    public static Texture2D MergeTexture(Texture2D mainTex, Color[] colors)
    {
        int width = mainTex.width;
        int height = mainTex.height;
        Texture2D newTex = new Texture2D(mainTex.width, mainTex.height, TextureFormat.ARGB32, false);
        Color[] colorMerge = new Color[width * height];
        Color[] colorsBase = mainTex.GetPixels();
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++)
            {
                int cursor = x + y * width;

                if (cursor < colorsBase.Length)
                {
                    colorMerge[cursor] += colorsBase[cursor] * colorsBase[cursor].a;
                }
                if (cursor < colors.Length)
                {
                    colorMerge[cursor] += colors[cursor] * colors[cursor].a;
                }
            }


        newTex.SetPixels(colorMerge);
        return newTex;
    }
    /// <summary>
    /// 快速融合Tex，一开始，缺透明通道
    /// </summary>
    /// <param name="tt1"></param>
    /// <param name="tt2"></param>
    /// <param name="offsetX"></param>
    /// <param name="offsetY"></param>
    /// <returns></returns>
    public static Texture2D MergeTexture(Texture2D tt1, Texture2D tt2, int offsetX, int offsetY,bool isUseMainTexSize = false)
    {
        if (tt1==null || tt2 == null) return null;
        int width = 0;
        if (isUseMainTexSize)
            width = tt1.width;
        else
            width = Mathf.Max(tt1.width, tt2.width);
        int height = 0;
        if (isUseMainTexSize)
            height = tt1.height;
        else
            height = Mathf.Max(tt1.height, tt2.height);
        //Texture2D newTex = new Texture2D(width, height, TextureFormat.ARGB32, false);
        Texture2D newTex = new Texture2D(width, height, tt1.format, false);
        Color[] colorsBase = tt1.GetPixels();

        //Color32[] colors2 = tt2.GetPixels32(); //暂时不知道32位什么作用？？？
        Color[] colors2 = tt2.GetPixels();
        Color[] colors = new Color[width * height];
        Debug.Log(string.Format("offX=" + offsetX + "|offY=" + offsetY+"<-{0}({1})",tt2.height,height));
        for (int x = 0; x < width; x++)
            for (int y = 0; y < height; y++)
            {
                int cursor = x + y * width;

                if (cursor < colorsBase.Length)
                {
                    //colors[cursor] += colorsBase[x + y * width];

                    if (x + offsetX >= 0 && y + offsetY >= 0 && x + offsetX < tt1.width && y + offsetY < tt1.height)
                    {
                        int c1 = x + offsetX + (y + offsetY) * tt1.width;
                        //if (colorsBase[c1].a == 0)
                        //{
                        //    colors[cursor] += colorsBase[c1];
                        //}
                        //else
                        //{
                            colors[cursor] += colorsBase[c1] * colorsBase[c1].a;
                        //}
                    }
                }
                if (cursor < colors2.Length)
                {
                    //if (y + offsetY <= tt2.height)
                    {
                        if (x + offsetX >= 0 && y + offsetY >= 0 && x + offsetX < tt2.width && y + offsetY < tt2.height)
                        {

                            //原数据的色彩点，和目标的色彩点的长宽是不一样的（需要取原色彩点矩阵）
                            int c2 = x + offsetX + (y + offsetY) * tt2.width;
                            colors[cursor] += colors2[c2] * colors2[c2].a;
                        }
                    }
                }
            }

        newTex.SetPixels(0, 0, width, height, colors);
        newTex.Apply();

        return newTex;
    }
   
    public static Texture2D MergeTexture(Texture2D tt1, Texture2D tt2,bool isUseMainTexSize = false)
    {
        return MergeTexture(tt1, tt2, 0, 0,isUseMainTexSize);
    }

    /// <summary>
    /// 溶合2个Tex，GPU执行的方案
    /// </summary>
    public void DrawTexture2D()
    {
        //rt = new RenderTexture(1024, 1024, 32);           //Create RenderTexture 512x512 pixels in size.
        //GameObject.Find("obj001").GetComponent<Renderer>().material.mainTexture = rt;   //Assign my RenderTexure to be the main texture of my object.
        //RenderTexture.active = rt;
        //Graphics.Blit(texture, rt);          //Blit my starting texture to my RenderTexture.
        //RenderTexture.active = rt;                      //Set my RenderTexture active so DrawTexture will draw to it.
        //GL.PushMatrix();                                //Saves both projection and modelview matrices to the matrix stack.
        //GL.LoadPixelMatrix(0, 1024, 1024, 0);            //Setup a matrix for pixel-correct rendering.
        //                                                 //Draw my stampTexture on my RenderTexture positioned by posX and posY.
        //Graphics.DrawTexture(new Rect(posX, posY, stampTexture.width, stampTexture.height), stampTexture);
        //Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
        //png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
        //System.IO.File.WriteAllBytes(Application.dataPath + "/" + "nihao.png", png.EncodeToPNG());
        //GL.PopMatrix();
        ////Restores both projection and modelview matrices off the top of the matrix stack.
        //RenderTexture.active = null;                    //De-activate my RenderTexture.  
    }


    #endregion

    public static IEnumerator LoadTexture(string path,Action<Texture> cb) {
        //加上项目内相对路径
        if (path.StartsWith("Assets/"))
        {
            path = Application.dataPath + "/../" + path;
        }
        WWW ww = new WWW("file://" + path);
        //yield return null;
        while (!ww.isDone)
        {
            yield return new WaitForSeconds(0.1f);
        }
        if (ww != null && string.IsNullOrEmpty(ww.error))
        {
            cb(ww.texture);
        }
        else
        {
            Debug.LogError("无法加载贴图");
            Debug.LogError(ww.error);
        //TODO:反而不能取项目内资源
            cb(null);
        }


    }
    public static Texture2D ScaleTexture(Texture2D source,float scale) {
        if (source == null) return null;
        int width = Mathf.FloorToInt(source.width * scale);
        int height = Mathf.FloorToInt(source.height * scale);
        return ScaleTexture(source, width, height);
    }
    public static Texture2D ScaleTexture(Texture2D source, int targetWidth, int targetHeight)
    {
        Texture2D result = new Texture2D(targetWidth, targetHeight, source.format, false);

        float incX = (1.0f / (float)targetWidth);
        float incY = (1.0f / (float)targetHeight);

        for (int i = 0; i < result.height; ++i)
        {
            for (int j = 0; j < result.width; ++j)
            {
                Color newColor = source.GetPixelBilinear((float)j / (float)result.width, (float)i / (float)result.height);
                result.SetPixel(j, i, newColor);
            }
        }

        result.Apply();
        return result;
    }

    /// <summary>
    /// TODO:覆盖如何做？？
    /// </summary>
    /// <param name="texture"></param>
    /// <param name="filePath"></param>

    public static void SaveTextureToFile(Texture2D texture,string filePath)
    {
        var bytes = texture.EncodeToPNG();
        var file = new FileStream(filePath, FileMode.Create);
        var binary = new BinaryWriter(file);
        binary.Write(bytes);
        file.Close();
    }

    
    
}
